package tenumn.energytech.compat;

import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f;
import mcjty.theoneprobe.api.*;
import mcjty.theoneprobe.apiimpl.ProbeConfig;
import mcjty.theoneprobe.apiimpl.TheOneProbeImp;
import mcjty.theoneprobe.apiimpl.styles.ProgressStyle;
import mcjty.theoneprobe.config.Config;
import mcjty.theoneprobe.rendering.RenderHelper;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.fluids.FluidStack;
import tenumn.energytech.EnergyTech;
import tenumn.energytech.registrys.CapabilitiesRegistry;

import java.text.DecimalFormat;
import java.util.Objects;

public class TOPProvider implements IProbeInfoProvider {
    public static TheOneProbeImp impl;

    public static Void initImpl(TheOneProbeImp impl) {
        TOPProvider.impl = impl;
        impl.registerElementFactory(ElementProgressFloat.factory());
        impl.registerProvider(new TOPProvider());
        return null;
    }

    @Override
    public ResourceLocation getID() {
        return new ResourceLocation(EnergyTech.ID, EnergyTech.ID);
    }

    @Override
    public void addProbeInfo(ProbeMode probeMode, IProbeInfo iProbeInfo, Player player, Level level, BlockState blockState, IProbeHitData iProbeHitData) {
        showTankInfo(iProbeInfo, level, iProbeHitData.getPos(),iProbeHitData.getSideHit());
        showHeart(iProbeInfo,level,iProbeHitData.getPos(),iProbeHitData.getSideHit());
    }

    private void showTankInfo(IProbeInfo probeInfo, Level world, BlockPos pos, Direction direction) {
        ProbeConfig config = Config.getDefaultConfig();
        BlockEntity te = world.getBlockEntity(pos);
        if (te != null && te.getCapability(CapabilitiesRegistry.GAS_CAPABILITY,direction).isPresent()) {
            te.getCapability(CapabilitiesRegistry.GAS_CAPABILITY,direction).ifPresent((handler) -> {
                for (int i = 0; i < handler.getTanks(); ++i) {
                    FluidStack fluidStack = handler.getFluidInTank(i);
                    int maxContents = handler.getTankCapacity(i);
                    if (!fluidStack.isEmpty()) {
                        this.addGasInfo(probeInfo, config, fluidStack, maxContents);
                    }
                }

            });
        }

    }

    private void addGasInfo(IProbeInfo probeInfo, ProbeConfig config, FluidStack fluidStack, int maxContents) {
        int contents = fluidStack.getAmount();
        if (config.getTankMode() == 1) {
            Color color = new Color(fluidStack.getFluid().getAttributes().getColor(fluidStack));
            if (Objects.equals(fluidStack.getFluid(), Fluids.LAVA)) {
                color = new Color(255, 139, 27);
            }

            MutableComponent text = new TextComponent("");
            text.append(ElementProgressFloat.format(contents, Config.tankFormat.get(), new TextComponent("mB")));
            text.append("/");
            text.append(ElementProgressFloat.format(maxContents, Config.tankFormat.get(), new TextComponent("mB")));
            probeInfo.tankSimple(maxContents, fluidStack, probeInfo.defaultProgressStyle().numberFormat(NumberFormat.NONE).borderlessColor(color, color.darker().darker()).prefix(((MutableComponent) fluidStack.getDisplayName()).append(": ")).suffix(text));
        } else {
            if (!fluidStack.isEmpty()) {
                probeInfo.text(CompoundText.create().style(TextStyleClass.NAME).text("Gas:").info(fluidStack.getTranslationKey()));
            }

            if (config.getTankMode() == 2) {
                probeInfo.progress(contents, maxContents, probeInfo.defaultProgressStyle().suffix("mB").filledColor(Config.tankbarFilledColor).alternateFilledColor(Config.tankbarAlternateFilledColor).borderColor(Config.tankbarBorderColor).numberFormat(Config.tankFormat.get()));
            } else {
                probeInfo.text(CompoundText.create().style(TextStyleClass.PROGRESS).text(ElementProgressFloat.format(contents, Config.tankFormat.get(), new TextComponent("mB"))));
            }
        }

    }
    private void showHeart(IProbeInfo probeInfo, Level world, BlockPos pos,Direction direction) {
        BlockEntity te = world.getBlockEntity(pos);
        if (te != null && te.getCapability(CapabilitiesRegistry.HEART_CAPABILITY,direction).isPresent()) {
            te.getCapability(CapabilitiesRegistry.HEART_CAPABILITY,direction).ifPresent((capabilityHeart) -> this.addHeartInfo(probeInfo, capabilityHeart.getTemperature(),capabilityHeart.getMax()));
        }

    }

    private void addHeartInfo(IProbeInfo probeInfo, float temperature, float maxTemperature) {
            probeInfo.element(new ElementProgressFloat(temperature, maxTemperature, probeInfo.defaultProgressStyle().suffix(" HU").filledColor(Config.rfbarFilledColor).alternateFilledColor(Config.rfbarAlternateFilledColor).borderColor(Color.rgb(255,0,51)).numberFormat(NumberFormat.FULL)));
    }

    public static final class ElementProgressFloat implements IElement {
        private static final DecimalFormat dfCommas = new DecimalFormat("###,###");

        public static Component format(float in, NumberFormat style, Component suffix) {
            switch (style) {
                case FULL:
                    return (new TextComponent(Float.toString(in))).append(suffix);
                case COMPACT:
                    if (in < 1000L) {
                        return (new TextComponent(in + " ")).append(suffix);
                    } else {
                        int unit = 1000;
                        int exp = (int) (Math.log(in) / Math.log(unit));
                        String s = suffix.getString();
                        char pre;
                        if (s.startsWith("m")) {
                            s = s.substring(1);
                            if (exp - 2 >= 0) {
                                pre = "kMGTPE".charAt(exp - 2);
                                return (new TextComponent(String.format("%.1f %s", in / Math.pow(unit, exp), pre))).append((new TextComponent(s)).withStyle(suffix.getStyle()));
                            }

                            return (new TextComponent(String.format("%.1f", in / Math.pow(unit, exp)))).append((new TextComponent(s)).withStyle(suffix.getStyle()));
                        }

                        pre = "kMGTPE".charAt(exp - 1);
                        return (new TextComponent(String.format("%.1f %s", in / Math.pow(unit, exp), pre))).append(suffix);
                    }
                case COMMAS:
                    return (new TextComponent(dfCommas.format(in))).append(suffix);
                case NONE:
                    return suffix;
                default:
                    return new TextComponent(Float.toString(in));
            }
        }

        public void render(PoseStack matrixStack, int x, int y) {
            render(this.style, this.current, this.max, matrixStack, x, y, this.getWidth(), this.getHeight());
        }

        public static void render(IProgressStyle style, float current, float max, PoseStack matrixStack, int x, int y, int w, int h) {
            if (style.isLifeBar()) {
                renderLifeBar(current, matrixStack, x, y, w);
            } else if (style.isArmorBar()) {
                renderArmorBar(current, matrixStack, x, y, w);
            } else {
                RenderHelper.drawThickBeveledBox(matrixStack, x, y, x + w, y + h, 1, style.getBorderColor(), style.getBorderColor(), style.getBackgroundColor());
                if (current > 0L && max > 0L) {
                    int dx = (int) Math.min(current * (long) (w - 2) / max, (long) (w - 2));
                    if (style.getFilledColor() == style.getAlternatefilledColor()) {
                        if (dx > 0) {
                            RenderHelper.drawThickBeveledBox(matrixStack, x + 1, y + 1, x + dx + 1, y + h - 1, 1, style.getFilledColor(), style.getFilledColor(), style.getFilledColor());
                        }
                    } else {
                        for (int xx = x + 1; xx < x + dx + 1; ++xx) {
                            int color = (xx & 1) == 0 ? style.getFilledColor() : style.getAlternatefilledColor();
                            RenderHelper.drawVerticalLine(matrixStack, xx, y + 1, y + h - 1, color);
                        }
                    }
                }
            }

            renderText(matrixStack, x, y, w, current, style);
        }

        private static final ResourceLocation ICONS = new ResourceLocation("textures/gui/icons.png");
        private final float current;
        private final float max;
        private final IProgressStyle style;
        private static final ResourceLocation resourceLocation=new ResourceLocation(EnergyTech.ID,"element_progress_float");
        public ElementProgressFloat(float current, float max,
                                    IProgressStyle style) {
            this.current = current;
            this.max = max;
            this.style = style;
        }
        public ElementProgressFloat(FriendlyByteBuf buf) {
            this.current = buf.readFloat();
            this.max = buf.readFloat();
            this.style = (new ProgressStyle()).width(buf.readInt()).height(buf.readInt()).prefix(buf.readComponent()).suffix(buf.readComponent()).borderColor(buf.readInt()).filledColor(buf.readInt()).alternateFilledColor(buf.readInt()).backgroundColor(buf.readInt()).showText(buf.readBoolean()).numberFormat(NumberFormat.values()[buf.readByte()]).lifeBar(buf.readBoolean()).armorBar(buf.readBoolean()).alignment(buf.readEnum(ElementAlignment.class));
        }
        public static IElementFactory factory(){
            return new IElementFactory() {
                @Override
                public IElement createElement(FriendlyByteBuf friendlyByteBuf) {
                    return new ElementProgressFloat(friendlyByteBuf);
                }
                 @Override
                public ResourceLocation getId() {
                    return resourceLocation;
                }
            };
        }
        private static void renderLifeBar(float current, PoseStack matrixStack, int x, int y, int w) {
            RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
            RenderSystem.setShaderTexture(0, ICONS);
            Matrix4f matrix = matrixStack.last().pose();
            if (current * 4L >= w) {
                RenderHelper.drawTexturedModalRect(matrix, x, y, 52, 0, 9, 9);
                Minecraft var10000 = Minecraft.getInstance();
                int var10002 = x + 12;
                ChatFormatting var10004 = ChatFormatting.WHITE;
                RenderHelper.renderText(var10000, matrixStack, var10002, y, var10004 + String.valueOf(current / 2L));
            } else {
                for (int i = 0; i < current / 2L; ++i) {
                    RenderHelper.drawTexturedModalRect(matrix, x, y, 52, 0, 9, 9);
                    x += 8;
                }

                if (current % 2L != 0L) {
                    RenderHelper.drawTexturedModalRect(matrix, x, y, 61, 0, 9, 9);
                }
            }

        }

        private static void renderArmorBar(float current, PoseStack matrixStack, int x, int y, int w) {
            RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
            RenderSystem.setShaderTexture(0, ICONS);
            Matrix4f matrix = matrixStack.last().pose();
            if (current * 4L >= (long) w) {
                RenderHelper.drawTexturedModalRect(matrix, x, y, 43, 9, 9, 9);
                Minecraft var10000 = Minecraft.getInstance();
                int var10002 = x + 12;
                ChatFormatting var10004 = ChatFormatting.WHITE;
                RenderHelper.renderText(var10000, matrixStack, var10002, y, var10004 + String.valueOf(current / 2L));
            } else {
                for (int i = 0; (long) i < current / 2L; ++i) {
                    RenderHelper.drawTexturedModalRect(matrix, x, y, 43, 9, 9, 9);
                    x += 8;
                }

                if (current % 2L != 0L) {
                    RenderHelper.drawTexturedModalRect(matrix, x, y, 25, 9, 9, 9);
                }
            }

        }

        private static void renderText(PoseStack matrixStack, int x, int y, int w, float current, IProgressStyle style) {
            if (style.isShowText()) {
                Minecraft mc = Minecraft.getInstance();
                Font render = mc.font;
                Component s = style.getPrefixComp().copy().append(format(current, style.getNumberFormat(), style.getSuffixComp()));
                int textWidth = render.width(s.getVisualOrderText());
                switch (style.getAlignment()) {
                    case ALIGN_BOTTOMRIGHT -> RenderHelper.renderText(mc, matrixStack, x + w - 3 - textWidth, y + 2, s);
                    case ALIGN_CENTER -> RenderHelper.renderText(mc, matrixStack, x + w / 2 - textWidth / 2, y + 2, s);
                    case ALIGN_TOPLEFT -> RenderHelper.renderText(mc, matrixStack, x + 3, y + 2, s);
                }
            }

        }

        public int getWidth() {
            if (this.style.isLifeBar()) {
                return this.current * 4L >= this.style.getWidth() ? 100 : (int) (this.current * 4L + 2L);
            } else {
                return this.style.getWidth();
            }
        }

        public int getHeight() {
            return this.style.getHeight();
        }

        public void toBytes(FriendlyByteBuf buf) {
            buf.writeFloat(this.current);
            buf.writeFloat(this.max);
            buf.writeInt(this.style.getWidth());
            buf.writeInt(this.style.getHeight());
            buf.writeComponent(this.style.getPrefixComp());
            buf.writeComponent(this.style.getSuffixComp());
            buf.writeInt(this.style.getBorderColor());
            buf.writeInt(this.style.getFilledColor());
            buf.writeInt(this.style.getAlternatefilledColor());
            buf.writeInt(this.style.getBackgroundColor());
            buf.writeBoolean(this.style.isShowText());
            buf.writeByte(this.style.getNumberFormat().ordinal());
            buf.writeBoolean(this.style.isLifeBar());
            buf.writeBoolean(this.style.isArmorBar());
            buf.writeEnum(this.style.getAlignment());
        }
        @Override
        public ResourceLocation getID() {
            return resourceLocation;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) return true;
            if (obj == null || obj.getClass() != this.getClass()) return false;
            var that = (ElementProgressFloat) obj;
            return Float.floatToIntBits(this.current) == Float.floatToIntBits(that.current) &&
                    Float.floatToIntBits(this.max) == Float.floatToIntBits(that.max) &&
                    Objects.equals(this.style, that.style);
        }

        @Override
        public int hashCode() {
            return Objects.hash(current, max, style);
        }

        @Override
        public String toString() {
            return "ElementProgressFloat[" +
                    "current=" + current + ", " +
                    "max=" + max + ", " +
                    "style=" + style + ']';
        }

    }

}
